﻿using System;
using Microsoft.Xna.Framework;

namespace Terraria.Utilities
{
	// Token: 0x020000CF RID: 207
	public static class NPCUtils
	{
		// Token: 0x06000ADC RID: 2780 RVA: 0x0000B993 File Offset: 0x00009B93
		public static NPCUtils.TargetSearchResults SearchForTarget(Vector2 position, NPCUtils.TargetSearchFlag flags = NPCUtils.TargetSearchFlag.All, NPCUtils.SearchFilter<Player> playerFilter = null, NPCUtils.SearchFilter<NPC> npcFilter = null)
		{
			return NPCUtils.SearchForTarget(null, position, flags, playerFilter, npcFilter);
		}

		// Token: 0x06000ADD RID: 2781 RVA: 0x0000B99F File Offset: 0x00009B9F
		public static NPCUtils.TargetSearchResults SearchForTarget(NPC searcher, NPCUtils.TargetSearchFlag flags = NPCUtils.TargetSearchFlag.All, NPCUtils.SearchFilter<Player> playerFilter = null, NPCUtils.SearchFilter<NPC> npcFilter = null)
		{
			return NPCUtils.SearchForTarget(searcher, searcher.Center, flags, playerFilter, npcFilter);
		}

		// Token: 0x06000ADE RID: 2782 RVA: 0x003E7538 File Offset: 0x003E5738
		public static NPCUtils.TargetSearchResults SearchForTarget(NPC searcher, Vector2 position, NPCUtils.TargetSearchFlag flags = NPCUtils.TargetSearchFlag.All, NPCUtils.SearchFilter<Player> playerFilter = null, NPCUtils.SearchFilter<NPC> npcFilter = null)
		{
			float num = float.MaxValue;
			int nearestNPCIndex = -1;
			float num2 = float.MaxValue;
			float nearestTankDistance = float.MaxValue;
			int nearestTankIndex = -1;
			NPCUtils.TargetType tankType = NPCUtils.TargetType.Player;
			if (flags.HasFlag(NPCUtils.TargetSearchFlag.NPCs))
			{
				for (int i = 0; i < 200; i++)
				{
					NPC npc = Main.npc[i];
					if (npc.active && (npcFilter == null || npcFilter(npc)))
					{
						float num3 = Vector2.DistanceSquared(position, npc.Center);
						if (num3 < num)
						{
							nearestNPCIndex = i;
							num = num3;
						}
					}
				}
			}
			if (flags.HasFlag(NPCUtils.TargetSearchFlag.Players))
			{
				for (int j = 0; j < 255; j++)
				{
					Player player = Main.player[j];
					if (player.active && !player.dead && !player.ghost && (playerFilter == null || playerFilter(player)))
					{
						float num4 = Vector2.Distance(position, player.Center);
						float num5 = num4 - (float)player.aggro;
						bool flag = searcher != null && player.npcTypeNoAggro[searcher.type];
						if (searcher != null && flag && searcher.direction == 0)
						{
							num5 += 1000f;
						}
						if (num5 < num2)
						{
							nearestTankIndex = j;
							num2 = num5;
							nearestTankDistance = num4;
							tankType = NPCUtils.TargetType.Player;
						}
						if (player.tankPet >= 0 && !flag)
						{
							Vector2 center = Main.projectile[player.tankPet].Center;
							num4 = Vector2.Distance(position, center);
							num5 = num4 - 200f;
							if (num5 < num2 && num5 < 200f && Collision.CanHit(position, 0, 0, center, 0, 0))
							{
								nearestTankIndex = j;
								num2 = num5;
								nearestTankDistance = num4;
								tankType = NPCUtils.TargetType.TankPet;
							}
						}
					}
				}
			}
			return new NPCUtils.TargetSearchResults(searcher, nearestNPCIndex, (float)Math.Sqrt((double)num), nearestTankIndex, nearestTankDistance, num2, tankType);
		}

		// Token: 0x06000ADF RID: 2783 RVA: 0x003E7704 File Offset: 0x003E5904
		public static void TargetClosestOldOnesInvasion(NPC searcher, bool faceTarget = true, Vector2? checkPosition = null)
		{
			NPCUtils.TargetSearchResults targetSearchResults = NPCUtils.SearchForTarget(searcher, NPCUtils.TargetSearchFlag.All, NPCUtils.SearchFilters.OnlyPlayersInCertainDistance(searcher.Center, 200f), new NPCUtils.SearchFilter<NPC>(NPCUtils.SearchFilters.OnlyCrystal));
			if (!targetSearchResults.FoundTarget)
			{
				return;
			}
			searcher.target = targetSearchResults.NearestTargetIndex;
			searcher.targetRect = targetSearchResults.NearestTargetHitbox;
			if (searcher.ShouldFaceTarget(ref targetSearchResults, null) && faceTarget)
			{
				searcher.FaceTarget();
			}
		}

		// Token: 0x06000AE0 RID: 2784 RVA: 0x003E7774 File Offset: 0x003E5974
		public static void TargetClosestBetsy(NPC searcher, bool faceTarget = true, Vector2? checkPosition = null)
		{
			NPCUtils.TargetSearchResults targetSearchResults = NPCUtils.SearchForTarget(searcher, NPCUtils.TargetSearchFlag.All, null, new NPCUtils.SearchFilter<NPC>(NPCUtils.SearchFilters.OnlyCrystal));
			if (!targetSearchResults.FoundTarget)
			{
				return;
			}
			NPCUtils.TargetType value = targetSearchResults.NearestTargetType;
			if (targetSearchResults.FoundTank && !targetSearchResults.NearestTankOwner.dead)
			{
				value = NPCUtils.TargetType.Player;
			}
			searcher.target = targetSearchResults.NearestTargetIndex;
			searcher.targetRect = targetSearchResults.NearestTargetHitbox;
			if (searcher.ShouldFaceTarget(ref targetSearchResults, new NPCUtils.TargetType?(value)) && faceTarget)
			{
				searcher.FaceTarget();
			}
		}

		// Token: 0x020000D0 RID: 208
		// (Invoke) Token: 0x06000AE2 RID: 2786
		public delegate bool SearchFilter<T>(T entity) where T : Entity;

		// Token: 0x020000D1 RID: 209
		public static class SearchFilters
		{
			// Token: 0x06000AE5 RID: 2789 RVA: 0x0000B9B0 File Offset: 0x00009BB0
			public static bool OnlyCrystal(NPC npc)
			{
				return npc.type == 548 && !npc.dontTakeDamageFromHostiles;
			}

			// Token: 0x06000AE6 RID: 2790 RVA: 0x003E77F4 File Offset: 0x003E59F4
			public static NPCUtils.SearchFilter<Player> OnlyPlayersInCertainDistance(Vector2 position, float maxDistance)
			{
				return (Player player) => player.Distance(position) <= maxDistance;
			}
		}

		// Token: 0x020000D3 RID: 211
		public enum TargetType
		{
			// Token: 0x04000F38 RID: 3896
			None,
			// Token: 0x04000F39 RID: 3897
			NPC,
			// Token: 0x04000F3A RID: 3898
			Player,
			// Token: 0x04000F3B RID: 3899
			TankPet
		}

		// Token: 0x020000D4 RID: 212
		public struct TargetSearchResults
		{
			// Token: 0x170000C5 RID: 197
			// (get) Token: 0x06000AE9 RID: 2793 RVA: 0x003E7824 File Offset: 0x003E5A24
			public int NearestTargetIndex
			{
				get
				{
					NPCUtils.TargetType nearestTargetType = this._nearestTargetType;
					if (nearestTargetType == NPCUtils.TargetType.NPC)
					{
						return this.NearestNPC.WhoAmIToTargettingIndex;
					}
					if (nearestTargetType - NPCUtils.TargetType.Player > 1)
					{
						return -1;
					}
					return this._nearestTankIndex;
				}
			}

			// Token: 0x170000C6 RID: 198
			// (get) Token: 0x06000AEA RID: 2794 RVA: 0x003E7858 File Offset: 0x003E5A58
			public Rectangle NearestTargetHitbox
			{
				get
				{
					switch (this._nearestTargetType)
					{
					case NPCUtils.TargetType.NPC:
						return this.NearestNPC.Hitbox;
					case NPCUtils.TargetType.Player:
						return this.NearestTankOwner.Hitbox;
					case NPCUtils.TargetType.TankPet:
						return Main.projectile[this.NearestTankOwner.tankPet].Hitbox;
					default:
						return Rectangle.Empty;
					}
				}
			}

			// Token: 0x170000C7 RID: 199
			// (get) Token: 0x06000AEB RID: 2795 RVA: 0x0000B9E3 File Offset: 0x00009BE3
			public NPCUtils.TargetType NearestTargetType
			{
				get
				{
					return this._nearestTargetType;
				}
			}

			// Token: 0x170000C8 RID: 200
			// (get) Token: 0x06000AEC RID: 2796 RVA: 0x0000B9EB File Offset: 0x00009BEB
			public bool FoundTarget
			{
				get
				{
					return this._nearestTargetType > NPCUtils.TargetType.None;
				}
			}

			// Token: 0x170000C9 RID: 201
			// (get) Token: 0x06000AED RID: 2797 RVA: 0x0000B9F6 File Offset: 0x00009BF6
			public NPC NearestNPC
			{
				get
				{
					if (this._nearestNPCIndex != -1)
					{
						return Main.npc[this._nearestNPCIndex];
					}
					return null;
				}
			}

			// Token: 0x170000CA RID: 202
			// (get) Token: 0x06000AEE RID: 2798 RVA: 0x0000BA0F File Offset: 0x00009C0F
			public bool FoundNPC
			{
				get
				{
					return this._nearestNPCIndex != -1;
				}
			}

			// Token: 0x170000CB RID: 203
			// (get) Token: 0x06000AEF RID: 2799 RVA: 0x0000BA1D File Offset: 0x00009C1D
			public int NearestNPCIndex
			{
				get
				{
					return this._nearestNPCIndex;
				}
			}

			// Token: 0x170000CC RID: 204
			// (get) Token: 0x06000AF0 RID: 2800 RVA: 0x0000BA25 File Offset: 0x00009C25
			public float NearestNPCDistance
			{
				get
				{
					return this._nearestNPCDistance;
				}
			}

			// Token: 0x170000CD RID: 205
			// (get) Token: 0x06000AF1 RID: 2801 RVA: 0x0000BA2D File Offset: 0x00009C2D
			public Player NearestTankOwner
			{
				get
				{
					if (this._nearestTankIndex != -1)
					{
						return Main.player[this._nearestTankIndex];
					}
					return null;
				}
			}

			// Token: 0x170000CE RID: 206
			// (get) Token: 0x06000AF2 RID: 2802 RVA: 0x0000BA46 File Offset: 0x00009C46
			public bool FoundTank
			{
				get
				{
					return this._nearestTankIndex != -1;
				}
			}

			// Token: 0x170000CF RID: 207
			// (get) Token: 0x06000AF3 RID: 2803 RVA: 0x0000BA54 File Offset: 0x00009C54
			public int NearestTankOwnerIndex
			{
				get
				{
					return this._nearestTankIndex;
				}
			}

			// Token: 0x170000D0 RID: 208
			// (get) Token: 0x06000AF4 RID: 2804 RVA: 0x0000BA5C File Offset: 0x00009C5C
			public float NearestTankDistance
			{
				get
				{
					return this._nearestTankDistance;
				}
			}

			// Token: 0x170000D1 RID: 209
			// (get) Token: 0x06000AF5 RID: 2805 RVA: 0x0000BA64 File Offset: 0x00009C64
			public float AdjustedTankDistance
			{
				get
				{
					return this._adjustedTankDistance;
				}
			}

			// Token: 0x170000D2 RID: 210
			// (get) Token: 0x06000AF6 RID: 2806 RVA: 0x0000BA6C File Offset: 0x00009C6C
			public NPCUtils.TargetType NearestTankType
			{
				get
				{
					return this._nearestTankType;
				}
			}

			// Token: 0x06000AF7 RID: 2807 RVA: 0x003E78B8 File Offset: 0x003E5AB8
			public TargetSearchResults(NPC searcher, int nearestNPCIndex, float nearestNPCDistance, int nearestTankIndex, float nearestTankDistance, float adjustedTankDistance, NPCUtils.TargetType tankType)
			{
				this._nearestNPCIndex = nearestNPCIndex;
				this._nearestNPCDistance = nearestNPCDistance;
				this._nearestTankIndex = nearestTankIndex;
				this._adjustedTankDistance = adjustedTankDistance;
				this._nearestTankDistance = nearestTankDistance;
				this._nearestTankType = tankType;
				if (this._nearestNPCIndex != -1 && this._nearestTankIndex != -1)
				{
					if (this._nearestNPCDistance < this._adjustedTankDistance)
					{
						this._nearestTargetType = NPCUtils.TargetType.NPC;
						return;
					}
					this._nearestTargetType = tankType;
					return;
				}
				else
				{
					if (this._nearestNPCIndex != -1)
					{
						this._nearestTargetType = NPCUtils.TargetType.NPC;
						return;
					}
					if (this._nearestTankIndex != -1)
					{
						this._nearestTargetType = tankType;
						return;
					}
					this._nearestTargetType = NPCUtils.TargetType.None;
					return;
				}
			}

			// Token: 0x04000F3C RID: 3900
			private NPCUtils.TargetType _nearestTargetType;

			// Token: 0x04000F3D RID: 3901
			private int _nearestNPCIndex;

			// Token: 0x04000F3E RID: 3902
			private float _nearestNPCDistance;

			// Token: 0x04000F3F RID: 3903
			private int _nearestTankIndex;

			// Token: 0x04000F40 RID: 3904
			private float _nearestTankDistance;

			// Token: 0x04000F41 RID: 3905
			private float _adjustedTankDistance;

			// Token: 0x04000F42 RID: 3906
			private NPCUtils.TargetType _nearestTankType;
		}

		// Token: 0x020000D5 RID: 213
		[Flags]
		public enum TargetSearchFlag
		{
			// Token: 0x04000F44 RID: 3908
			None = 0,
			// Token: 0x04000F45 RID: 3909
			NPCs = 1,
			// Token: 0x04000F46 RID: 3910
			Players = 2,
			// Token: 0x04000F47 RID: 3911
			All = 3
		}
	}
}
